/*
 * Copyright (c) 2009, Hamish Morgan. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the University of Sussex nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * MainMenu.java
 *
 * Created on 08-Sep-2009, 15:09:00
 */
package locusts;

import java.awt.CardLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.prefs.BackingStoreException;
import java.util.prefs.PreferenceChangeEvent;
import java.util.prefs.PreferenceChangeListener;
import java.util.prefs.Preferences;
import javax.swing.InputVerifier;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author Hamish Morgan
 */
public class MainMenu extends javax.swing.JFrame {

    private static final ResourceBundle strings = ResourceBundle.getBundle(
            "strings", Locale.getDefault());
    private static final Logger LOG = LoggerFactory.getLogger(MainMenu.class);
    private static final int HISTORY_SIZE = 5;
    private final Preferences prefs;
    private static final String ADDRESS_NAME = "address";
    private static final String PORT_NAME = "port";
    private static final String MODE_LOCAL = "modeLocal";
    private static final String MODE_SERVER = "modeServer";
    private static final String MODE_ADMIN = "modeAdmin";
    private static final String MODE_DEFAULT = MODE_LOCAL;
    private static final String MODE_NAME = "mode";

    /** Creates new form MainMenu */
    public MainMenu() {

        prefs = Preferences.userNodeForPackage(MainMenu.class);
        initComponents();


        prefs.addPreferenceChangeListener(new PreferenceChangeListener() {

            public void preferenceChange(PreferenceChangeEvent evt) {
                if (evt.getKey().matches("^" + PORT_NAME + "\\[[0-9]*\\]$"))
                    loadPorts();
                else if (evt.getKey().equals(MODE_NAME))
                    loadMode();
            }
        });

        ((JTextField) portComboBox.getEditor().
                getEditorComponent()).setInputVerifier(new InputVerifier() {

            @Override
            public boolean verify(JComponent input) {
                return isPortValid();
            }
        });

        ((JTextField) portComboBox1.getEditor().getEditorComponent()).
                setInputVerifier(((JTextField) portComboBox.getEditor().
                getEditorComponent()).getInputVerifier());

        final JTextField atf = (JTextField) addressComboBox.getEditor().
                getEditorComponent();
        atf.setInputVerifier(new InputVerifier() {

            @Override
            public boolean verify(JComponent input) {
                return isAddressValid();
            }
        });

        ActionListener updateButtons = new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                updateButtons();
            }
        };

        portComboBox.addActionListener(updateButtons);
        addressComboBox.addActionListener(updateButtons);
        modeLocalRadio.addActionListener(updateButtons);
        modeAdminRadio.addActionListener(updateButtons);
        modeServerRadio.addActionListener(updateButtons);

        portComboBox1.setModel(portComboBox.getModel());


        loadData();

        updateButtons();
    }

    private void updateButtons() {
        setError(null);
        startGameButton.setEnabled(isModeValid() && isPortValid());
        doJoinGameButton.setEnabled(isPortValid() && isAddressValid());

    }

    private void loadData() {
        loadPorts();
        loadMode();
        loadAddresses();
    }

    private void saveData() {
        savePorts();
        saveMode();
        saveAddresses();
    }

    private void setError(String message) {
        if (message == null) {
            errorTextLabel.setText("No Message");
            errorPanel.setVisible(false);
            errorPanel1.setVisible(false);
        } else {
            errorTextLabel.setText(message);
            errorPanel.setVisible(true);
            errorPanel1.setVisible(true);

        }
    }

    private boolean isModeValid() {
        boolean valid = modeButtonGroup.getSelection() != null;
        if (!valid) {
            setError(
                    "No mode is selected; you must select one to start a game.");
        }
        return valid;
    }

    private final String getMode() {
        if (modeLocalRadio.isSelected())
            return MODE_LOCAL;
        else if (modeServerRadio.isSelected())
            return MODE_SERVER;
        else if (modeAdminRadio.isSelected())
            return MODE_ADMIN;
        return MODE_DEFAULT;

    }

    private void loadMode() {
        String val = prefs.get(MODE_NAME, MODE_DEFAULT);
        if (val.equals(MODE_LOCAL))
            modeLocalRadio.setSelected(true);
        else if (val.equals(MODE_SERVER))
            modeServerRadio.setSelected(true);
        else if (val.equals(MODE_ADMIN))
            modeAdminRadio.setSelected(true);
        else
            modeLocalRadio.setSelected(true);
    }

    private void saveMode() {
        if (modeLocalRadio.isSelected())
            prefs.put(MODE_NAME, MODE_LOCAL);
        else if (modeServerRadio.isSelected())
            prefs.put(MODE_NAME, MODE_SERVER);
        else if (modeAdminRadio.isSelected())
            prefs.put(MODE_NAME, MODE_ADMIN);
    }

    private LinkedList<Integer> getPortList() {
        final LinkedList<Integer> ports = new LinkedList<Integer>();

        int i = 0;
        String key = PORT_NAME + "[" + i + "]";
        Integer value = -1;
        while ((value = prefs.getInt(key, -1)) != -1) {
            ports.add(value);
            key = PORT_NAME + "[" + (++i) + "]";
        }

        if (!ports.contains(Main.DEFAULT_PORT))
            ports.add(Main.DEFAULT_PORT);
        return ports;
    }

    private boolean isPortValid() {
        JTextField editor = (JTextField) portComboBox.getEditor().
                getEditorComponent();

        final String text;
        if (editor.isVisible())
            text = editor.getText();
        else
            text = (String) portComboBox.getSelectedItem();

        boolean valid = true;
        try {
            int value = Integer.parseInt(text);
            if (value <= 0 || value >= 65536) {
                valid = false;
                setError("Port field is invalid. Expecting an number " +
                        "between 1 and 65535 but found " + value + ".");
            }

        } catch (NumberFormatException e) {
            valid = false;
            setError("Port field is invalid. Expecting an integer " +
                    "between 1 and 65535 but found " + text + ".");
        }
        return valid;
    }

    private int getPort() {
        return Integer.parseInt((String) portComboBox.getSelectedItem());
    }

    private void loadPorts() {

        portComboBox.removeAllItems();
        for (Integer port : getPortList())
            portComboBox.addItem("" + port);

    }

    private void savePorts() {

        final LinkedList<Integer> ports = getPortList();
        final String selected = (String) portComboBox.getSelectedItem();
        final Integer port = Integer.valueOf(selected);
        if (ports.contains(port)) {
            final int index = ports.indexOf(port);
            if (index > 0) {
                ports.remove(index);
                ports.addFirst(port);
            }
        } else {
            ports.addFirst(port);
            while (ports.size() > HISTORY_SIZE)
                ports.removeLast();
        }
        for (int i = 0; i < ports.size(); i++) {
            final String key = PORT_NAME + "[" + i + "]";
            prefs.putInt(key, ports.get(i));
        }
        try {
            prefs.sync();
        } catch (BackingStoreException ex) {
            LOG.error(null, ex);
        }
    }

    //=======================
    private LinkedList<String> getAddressList() {
        final LinkedList<String> addresses = new LinkedList<String>();

        final String defaultValue = "";
        int i = 0;
        String key = ADDRESS_NAME + "[" + i + "]";
        String value = defaultValue;
        while ((value = prefs.get(key, defaultValue)) != defaultValue) {
            addresses.add(value);
            key = ADDRESS_NAME + "[" + (++i) + "]";
        }

        if (!addresses.contains(Main.DEFAULT_HOST))
            addresses.add(Main.DEFAULT_HOST);
        return addresses;
    }

    private boolean isAddressValid() {
        JTextField editor = (JTextField) addressComboBox.getEditor().
                getEditorComponent();

        final String text;
        if (editor.isVisible())
            text = editor.getText();
        else
            text = (String) addressComboBox.getSelectedItem();

        boolean valid = true;
        try {
            if (InetAddress.getByName(text) == null) {
                setError("Address field is invalid. Expecting either an IP " +
                        "address (e.g 192.168.0.1) or a host name (e.g" +
                        " www.google.com) but found " + text);
                valid = false;
            }
        } catch (UnknownHostException e) {
            setError("Address field is invalid. Expecting either an IP " +
                    "address (e.g 192.168.0.1) or a host name (e.g" +
                    " www.google.com) but found " + text);
            valid = false;
        }

        return valid;
    }

    private String getAddress() {
        return (String) addressComboBox.getSelectedItem();
    }

    private void loadAddresses() {

        addressComboBox.removeAllItems();
        for (String address : getAddressList())
            addressComboBox.addItem("" + address);

    }

    private void saveAddresses() {

        final LinkedList<String> addresses = getAddressList();
        final String address = (String) addressComboBox.getSelectedItem();
        if (addresses.contains(address)) {
            final int index = addresses.indexOf(address);
            if (index > 0) {
                addresses.remove(index);
                addresses.addFirst(address);
            }
        } else {
            addresses.addFirst(address);
            while (addresses.size() > HISTORY_SIZE)
                addresses.removeLast();
        }
        for (int i = 0; i < addresses.size(); i++) {
            final String key = ADDRESS_NAME + "[" + i + "]";
            prefs.put(key, addresses.get(i));
        }
        try {
            prefs.sync();
        } catch (BackingStoreException ex) {
            LOG.error(null, ex);
        }
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;
        bindingGroup = new org.jdesktop.beansbinding.BindingGroup();

        modeButtonGroup = new javax.swing.ButtonGroup();
        startTypePanel = new javax.swing.JPanel();
        startTypeTopPanel = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        startTypeCenterPanel = new javax.swing.JPanel();
        jLabel5 = new javax.swing.JLabel();
        startTypeBottomPanel = new javax.swing.JPanel();
        newGameButton = new javax.swing.JButton();
        joinGameButton = new javax.swing.JButton();
        exitButton = new javax.swing.JButton();
        newGamePanel = new javax.swing.JPanel();
        jPanel3 = new javax.swing.JPanel();
        newGameBackButton = new javax.swing.JButton();
        startGameButton = new javax.swing.JButton();
        jPanel4 = new javax.swing.JPanel();
        jLabel2 = new javax.swing.JLabel();
        jPanel5 = new javax.swing.JPanel();
        jPanel7 = new javax.swing.JPanel();
        portComboBox = new javax.swing.JComboBox();
        jLabel4 = new javax.swing.JLabel();
        jPanel8 = new javax.swing.JPanel();
        modeLocalRadio = new javax.swing.JRadioButton();
        jLabel7 = new javax.swing.JLabel();
        modeAdminRadio = new javax.swing.JRadioButton();
        jLabel9 = new javax.swing.JLabel();
        modeServerRadio = new javax.swing.JRadioButton();
        jLabel8 = new javax.swing.JLabel();
        errorPanel = new javax.swing.JPanel();
        errorTextLabel = new javax.swing.JLabel();
        joinGamePanel = new javax.swing.JPanel();
        jPanel1 = new javax.swing.JPanel();
        jButton1 = new javax.swing.JButton();
        doJoinGameButton = new javax.swing.JButton();
        jPanel2 = new javax.swing.JPanel();
        jLabel3 = new javax.swing.JLabel();
        jPanel6 = new javax.swing.JPanel();
        jPanel9 = new javax.swing.JPanel();
        portComboBox1 = new javax.swing.JComboBox();
        jLabel6 = new javax.swing.JLabel();
        addressComboBox = new javax.swing.JComboBox();
        jLabel10 = new javax.swing.JLabel();
        jLabel11 = new javax.swing.JLabel();
        errorPanel1 = new javax.swing.JPanel();
        errorTextLabel1 = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        getContentPane().setLayout(new java.awt.CardLayout());

        startTypePanel.setLayout(new java.awt.BorderLayout());

        jLabel1.setText("Welcome to Locusts");
        startTypeTopPanel.add(jLabel1);

        startTypePanel.add(startTypeTopPanel, java.awt.BorderLayout.NORTH);

        jLabel5.setIcon(new javax.swing.ImageIcon(getClass().getResource("/locusts/LocustLogo.png"))); // NOI18N
        startTypeCenterPanel.add(jLabel5);

        startTypePanel.add(startTypeCenterPanel, java.awt.BorderLayout.CENTER);

        newGameButton.setText("New Game");
        newGameButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                newGameButtonActionPerformed(evt);
            }
        });
        startTypeBottomPanel.add(newGameButton);

        joinGameButton.setText("Join Game");
        joinGameButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                joinGameButtonActionPerformed(evt);
            }
        });
        startTypeBottomPanel.add(joinGameButton);

        exitButton.setText("Exit");
        exitButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                exitButtonActionPerformed(evt);
            }
        });
        startTypeBottomPanel.add(exitButton);

        startTypePanel.add(startTypeBottomPanel, java.awt.BorderLayout.SOUTH);

        getContentPane().add(startTypePanel, "startTypeCard");

        newGamePanel.setLayout(new java.awt.BorderLayout());

        newGameBackButton.setText("Back");
        newGameBackButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                newGameBackButtonActionPerformed(evt);
            }
        });
        jPanel3.add(newGameBackButton);

        startGameButton.setText("Start");
        startGameButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                startGameButtonActionPerformed(evt);
            }
        });
        jPanel3.add(startGameButton);

        newGamePanel.add(jPanel3, java.awt.BorderLayout.SOUTH);

        jLabel2.setText("Create a new game");
        jPanel4.add(jLabel2);

        newGamePanel.add(jPanel4, java.awt.BorderLayout.NORTH);

        jPanel7.setBorder(javax.swing.BorderFactory.createTitledBorder("Port"));
        jPanel7.setLayout(new java.awt.GridBagLayout());

        portComboBox.setEditable(true);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
        jPanel7.add(portComboBox, gridBagConstraints);

        jLabel4.setFont(new java.awt.Font("Lucida Grande", 0, 10)); // NOI18N
        jLabel4.setText("<html>The port number identifies the Locusts game on this computer to clients wishing to join. Basically the port number must match between the client and server.You can ignore this if you are only playing a local game.</html>");
        jLabel4.setMinimumSize(null);
        jLabel4.setPreferredSize(null);
        jLabel4.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.ipadx = 5;
        gridBagConstraints.ipady = 5;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LAST_LINE_END;
        gridBagConstraints.weightx = 0.1;
        jPanel7.add(jLabel4, gridBagConstraints);

        jPanel8.setBorder(javax.swing.BorderFactory.createTitledBorder("Mode"));
        jPanel8.setLayout(new java.awt.GridBagLayout());

        modeButtonGroup.add(modeLocalRadio);
        modeLocalRadio.setText("Local Game");
        modeLocalRadio.setVerticalAlignment(javax.swing.SwingConstants.TOP);
        modeLocalRadio.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                modeLocalRadioActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
        jPanel8.add(modeLocalRadio, gridBagConstraints);

        jLabel7.setFont(new java.awt.Font("Lucida Grande", 0, 10));
        jLabel7.setText("<html>Start a new game server and a client on this computer. Other clients can still join the game but you will be unable to administer them.</html>");
        jLabel7.setMinimumSize(null);
        jLabel7.setPreferredSize(null);
        jLabel7.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.ipadx = 5;
        gridBagConstraints.ipady = 5;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_END;
        gridBagConstraints.weightx = 0.1;
        jPanel8.add(jLabel7, gridBagConstraints);

        modeButtonGroup.add(modeAdminRadio);
        modeAdminRadio.setText("Admin Server");
        modeAdminRadio.setVerticalAlignment(javax.swing.SwingConstants.TOP);
        modeAdminRadio.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
        modeAdminRadio.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                modeAdminRadioActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        jPanel8.add(modeAdminRadio, gridBagConstraints);

        jLabel9.setFont(new java.awt.Font("Lucida Grande", 0, 10));
        jLabel9.setText("<html>Start a new game server and run the administration tool. This includes a client view, as well as a number of ways altering the game. For example you can add locusts, change game properties, etc...</html>");
        jLabel9.setMinimumSize(null);
        jLabel9.setPreferredSize(null);
        jLabel9.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.ipadx = 5;
        gridBagConstraints.ipady = 5;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_END;
        gridBagConstraints.weightx = 0.1;
        jPanel8.add(jLabel9, gridBagConstraints);

        modeButtonGroup.add(modeServerRadio);
        modeServerRadio.setText("Dedicated Server");
        modeServerRadio.setVerticalAlignment(javax.swing.SwingConstants.TOP);
        modeServerRadio.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
        modeServerRadio.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                modeServerRadioActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LAST_LINE_START;
        jPanel8.add(modeServerRadio, gridBagConstraints);

        jLabel8.setFont(new java.awt.Font("Lucida Grande", 0, 10));
        jLabel8.setText("<html>Start only the server portion of the game. Clients must connect to play the game but you will not be able to do anything locally.</html>");
        jLabel8.setMinimumSize(null);
        jLabel8.setPreferredSize(null);
        jLabel8.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.ipadx = 5;
        gridBagConstraints.ipady = 5;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LAST_LINE_END;
        gridBagConstraints.weightx = 0.1;
        jPanel8.add(jLabel8, gridBagConstraints);

        errorPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Errors", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Lucida Grande", 0, 13), new java.awt.Color(255, 0, 0))); // NOI18N

        errorTextLabel.setForeground(new java.awt.Color(255, 0, 0));
        errorTextLabel.setText("Error text");

        org.jdesktop.layout.GroupLayout errorPanelLayout = new org.jdesktop.layout.GroupLayout(errorPanel);
        errorPanel.setLayout(errorPanelLayout);
        errorPanelLayout.setHorizontalGroup(
            errorPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(org.jdesktop.layout.GroupLayout.TRAILING, errorPanelLayout.createSequentialGroup()
                .addContainerGap()
                .add(errorTextLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 469, Short.MAX_VALUE)
                .addContainerGap())
        );
        errorPanelLayout.setVerticalGroup(
            errorPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(errorPanelLayout.createSequentialGroup()
                .add(errorTextLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 32, Short.MAX_VALUE)
                .addContainerGap())
        );

        org.jdesktop.layout.GroupLayout jPanel5Layout = new org.jdesktop.layout.GroupLayout(jPanel5);
        jPanel5.setLayout(jPanel5Layout);
        jPanel5Layout.setHorizontalGroup(
            jPanel5Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel5Layout.createSequentialGroup()
                .addContainerGap()
                .add(jPanel5Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, jPanel8, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 493, Short.MAX_VALUE)
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, jPanel7, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 493, Short.MAX_VALUE)
                    .add(errorPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addContainerGap())
        );
        jPanel5Layout.setVerticalGroup(
            jPanel5Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel5Layout.createSequentialGroup()
                .addContainerGap()
                .add(jPanel7, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jPanel8, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 152, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(errorPanel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .add(6, 6, 6))
        );

        newGamePanel.add(jPanel5, java.awt.BorderLayout.CENTER);

        getContentPane().add(newGamePanel, "newGameCard");

        joinGamePanel.setLayout(new java.awt.BorderLayout());

        jButton1.setText("Back");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });
        jPanel1.add(jButton1);

        doJoinGameButton.setText("Join");
        doJoinGameButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                doJoinGameButtonActionPerformed(evt);
            }
        });
        jPanel1.add(doJoinGameButton);

        joinGamePanel.add(jPanel1, java.awt.BorderLayout.SOUTH);

        jLabel3.setText("Join a game");
        jPanel2.add(jLabel3);

        joinGamePanel.add(jPanel2, java.awt.BorderLayout.NORTH);

        jPanel9.setBorder(javax.swing.BorderFactory.createTitledBorder("Connect To"));

        portComboBox1.setEditable(true);

        jLabel6.setFont(new java.awt.Font("Lucida Grande", 0, 10)); // NOI18N
        jLabel6.setText("<html>Enter the address and port of a Locusts server to connect to that game. The address is IP address of the server (e.g 192.168.0.1) or a domain name (google.com). The port is a number betwwen 1 and 65535 that identifies locusts on the server computer. The port number should match that used to start the server.</html>");
        jLabel6.setVerticalTextPosition(javax.swing.SwingConstants.TOP);

        addressComboBox.setEditable(true);

        jLabel10.setText("Address:");

        jLabel11.setText("Port:");

        org.jdesktop.layout.GroupLayout jPanel9Layout = new org.jdesktop.layout.GroupLayout(jPanel9);
        jPanel9.setLayout(jPanel9Layout);
        jPanel9Layout.setHorizontalGroup(
            jPanel9Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel9Layout.createSequentialGroup()
                .add(jPanel9Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(jPanel9Layout.createSequentialGroup()
                        .add(11, 11, 11)
                        .add(jLabel10)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
                        .add(addressComboBox, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .add(18, 18, 18)
                        .add(jLabel11)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(portComboBox1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                    .add(jPanel9Layout.createSequentialGroup()
                        .addContainerGap()
                        .add(jLabel6, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 469, Short.MAX_VALUE)))
                .addContainerGap())
        );
        jPanel9Layout.setVerticalGroup(
            jPanel9Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel9Layout.createSequentialGroup()
                .add(jPanel9Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(jLabel10)
                    .add(addressComboBox, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(jLabel11)
                    .add(portComboBox1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jLabel6)
                .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        errorPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Errors", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Lucida Grande", 0, 13), new java.awt.Color(255, 0, 0))); // NOI18N

        errorTextLabel1.setForeground(new java.awt.Color(255, 0, 0));

        org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, errorTextLabel, org.jdesktop.beansbinding.ELProperty.create("${text}"), errorTextLabel1, org.jdesktop.beansbinding.BeanProperty.create("text"));
        bindingGroup.addBinding(binding);

        org.jdesktop.layout.GroupLayout errorPanel1Layout = new org.jdesktop.layout.GroupLayout(errorPanel1);
        errorPanel1.setLayout(errorPanel1Layout);
        errorPanel1Layout.setHorizontalGroup(
            errorPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(org.jdesktop.layout.GroupLayout.TRAILING, errorPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .add(errorTextLabel1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 469, Short.MAX_VALUE)
                .addContainerGap())
        );
        errorPanel1Layout.setVerticalGroup(
            errorPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(errorPanel1Layout.createSequentialGroup()
                .add(errorTextLabel1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 151, Short.MAX_VALUE)
                .addContainerGap())
        );

        org.jdesktop.layout.GroupLayout jPanel6Layout = new org.jdesktop.layout.GroupLayout(jPanel6);
        jPanel6.setLayout(jPanel6Layout);
        jPanel6Layout.setHorizontalGroup(
            jPanel6Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel6Layout.createSequentialGroup()
                .addContainerGap()
                .add(jPanel9, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addContainerGap())
            .add(jPanel6Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                .add(jPanel6Layout.createSequentialGroup()
                    .addContainerGap()
                    .add(errorPanel1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addContainerGap()))
        );
        jPanel6Layout.setVerticalGroup(
            jPanel6Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel6Layout.createSequentialGroup()
                .addContainerGap()
                .add(jPanel9, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(201, Short.MAX_VALUE))
            .add(jPanel6Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                .add(org.jdesktop.layout.GroupLayout.TRAILING, jPanel6Layout.createSequentialGroup()
                    .addContainerGap(136, Short.MAX_VALUE)
                    .add(errorPanel1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .addContainerGap()))
        );

        joinGamePanel.add(jPanel6, java.awt.BorderLayout.CENTER);

        getContentPane().add(joinGamePanel, "joinGameCard");

        bindingGroup.bind();

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void joinGameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_joinGameButtonActionPerformed
        // TODO add your handling code here:
        ((CardLayout) getContentPane().getLayout()).show(getContentPane(),
                "joinGameCard");

    }//GEN-LAST:event_joinGameButtonActionPerformed

    private void exitButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitButtonActionPerformed
        setVisible(false);
        dispose();
        System.exit(0);
    }//GEN-LAST:event_exitButtonActionPerformed

    private void newGameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newGameButtonActionPerformed
        ((CardLayout) getContentPane().getLayout()).show(getContentPane(),
                "newGameCard");
    }//GEN-LAST:event_newGameButtonActionPerformed

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
        // TODO add your handling code here:
        ((CardLayout) getContentPane().getLayout()).show(getContentPane(),
                "startTypeCard");

    }//GEN-LAST:event_jButton1ActionPerformed

    private void newGameBackButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newGameBackButtonActionPerformed
        // TODO add your handling code here:
        ((CardLayout) getContentPane().getLayout()).show(getContentPane(),
                "startTypeCard");

    }//GEN-LAST:event_newGameBackButtonActionPerformed

    private void modeServerRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_modeServerRadioActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_modeServerRadioActionPerformed

    private void modeAdminRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_modeAdminRadioActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_modeAdminRadioActionPerformed

    private void modeLocalRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_modeLocalRadioActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_modeLocalRadioActionPerformed

    private void startGameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startGameButtonActionPerformed
        int port = getPort();
        String mode = getMode();
        try {
            if (mode.equals(MODE_LOCAL)) {
                Main.startLocal(port);
                setVisible(false);
                dispose();
                saveData();
            } else if (mode.equals(MODE_SERVER)) {
                Main.startServer(port);
                setVisible(false);
                dispose();

                JOptionPane.showMessageDialog(this,
                        "<html>The Locusts server is now running on port " +
                        port + ".<br /> Click OK to STOP the server.</html>",
                        "Server running...",
                        JOptionPane.INFORMATION_MESSAGE);
                saveData();
                System.exit(0);
            } else if (mode.equals(MODE_ADMIN)) {
                Main.startAdminServer(port);
                setVisible(false);
                dispose();
                saveData();
            }

        } catch (IOException ex) {
            LOG.error(null, ex);
        }
    }//GEN-LAST:event_startGameButtonActionPerformed

    private void doJoinGameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_doJoinGameButtonActionPerformed
        int port = getPort();
        String host = getAddress();
        Main.startClient(host, port);
        setVisible(false);
        dispose();
        saveData();

    }//GEN-LAST:event_doJoinGameButtonActionPerformed
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JComboBox addressComboBox;
    private javax.swing.JButton doJoinGameButton;
    private javax.swing.JPanel errorPanel;
    private javax.swing.JPanel errorPanel1;
    private javax.swing.JLabel errorTextLabel;
    private javax.swing.JLabel errorTextLabel1;
    private javax.swing.JButton exitButton;
    private javax.swing.JButton jButton1;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel10;
    private javax.swing.JLabel jLabel11;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JLabel jLabel7;
    private javax.swing.JLabel jLabel8;
    private javax.swing.JLabel jLabel9;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JPanel jPanel4;
    private javax.swing.JPanel jPanel5;
    private javax.swing.JPanel jPanel6;
    private javax.swing.JPanel jPanel7;
    private javax.swing.JPanel jPanel8;
    private javax.swing.JPanel jPanel9;
    private javax.swing.JButton joinGameButton;
    private javax.swing.JPanel joinGamePanel;
    private javax.swing.JRadioButton modeAdminRadio;
    private javax.swing.ButtonGroup modeButtonGroup;
    private javax.swing.JRadioButton modeLocalRadio;
    private javax.swing.JRadioButton modeServerRadio;
    private javax.swing.JButton newGameBackButton;
    private javax.swing.JButton newGameButton;
    private javax.swing.JPanel newGamePanel;
    private javax.swing.JComboBox portComboBox;
    private javax.swing.JComboBox portComboBox1;
    private javax.swing.JButton startGameButton;
    private javax.swing.JPanel startTypeBottomPanel;
    private javax.swing.JPanel startTypeCenterPanel;
    private javax.swing.JPanel startTypePanel;
    private javax.swing.JPanel startTypeTopPanel;
    private org.jdesktop.beansbinding.BindingGroup bindingGroup;
    // End of variables declaration//GEN-END:variables
}
